/// Blinky.NET - a program to reduce eye strain by reminding you to blink
/// Copyright (C) 2007  Forrest Humphrey
///
/// This program is free software; you can redistribute it and/or
/// modify it under the terms of the GNU General Public License
/// as published by the Free Software Foundation; either version 2
/// of the License, or (at your option) any later version.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the Free Software
/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
using System;
using System.Windows.Forms;
using Blinky.Properties;
using System.Diagnostics;

namespace Blinky {

    public delegate void TimeToBlinkHandler();

    /// <summary>
    /// 
    /// </summary>
    public sealed class ActivityTracker {
        private DateTime lastBlink;
        private DateTime nextBlinkTarget;
        private DateTime timeStoppedAccumulating;
        private Timer timer;
        private bool accumulateTime;
        public event TimeToBlinkHandler BlinkListeners;

        public ActivityTracker() {
            // I know there are tons of Timer objects in .net, but in leiu
            // of doing all the research to figure out which one fits best
            // here, I'm shamelessly using the one I know how to use.
            timer = new Timer();
            timer.Tick += new EventHandler(TimerTick);

            Reset();
            StopAccumulating();
            StartAccumulating();
        }

        /// <summary>
        /// This method causes all intervals to be retrieved from the
        /// user settings and restarts the timer.
        /// </summary>
        public void Reset() {
            timer.Stop();
            lastBlink = DateTime.Now;
            nextBlinkTarget =
                lastBlink + new TimeSpan(0, Settings.Default.BLINK_INTERVAL_M, 0);
            timer.Interval = Settings.Default.CHECK_IDLE_INTERVAL_S;
            timer.Interval = Settings.Default.CHECK_IDLE_INTERVAL_S * 1000;
            timer.Start();
        }

        // TODO: Reduce complexity
        // this is a fairly complex little series of conditions
        // I tried to break it up with tiny little cohesive
        // methods, but it still seems too hard to follow.
        private void TimerTick(object sender, EventArgs e) {
            if (accumulateTime) {
                if (HasUserLeft()) {
                    StopAccumulating();
                }
                else {
                    if (accumulateTime && ShouldBlink()) {
                        TellThemToBlink();
                    }
                }
            }
            else {
                if (!HasUserLeft()) {
                    StartAccumulating();
                }
            }
        }

        private TimeSpan GetElapsedTime() {
            return DateTime.Now - lastBlink;
        }

        private void TellThemToBlink() {
            timer.Stop();
            Debug.WriteLine("time to blink");
            BlinkListeners();
            lastBlink = DateTime.Now;
            nextBlinkTarget = lastBlink +
                new TimeSpan(0,Settings.Default.BLINK_INTERVAL_M,0);
            timer.Start();
        }

        private bool ShouldBlink() {
            return DateTime.Now.Ticks >= nextBlinkTarget.Ticks;
        }

        private void StartAccumulating() {
            accumulateTime = true;
            TimeSpan timeLeftBeforeBlink = nextBlinkTarget - timeStoppedAccumulating;
            nextBlinkTarget = DateTime.Now + timeLeftBeforeBlink;
            Debug.WriteLine("started accumulating");
        }

        private void StopAccumulating() {
            accumulateTime = false;
            timeStoppedAccumulating = DateTime.Now;
            Debug.WriteLine("stopped accumulating");
        }

        private bool HasUserLeft() {
            return IdleReporter.IdleTime > (Settings.Default.SUSPEND_TRACKING_INTERVAL_M * 60 * 1000);
        }
    }
}
